package com.canaan.business.service.inOutStock.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.canaan.business.common.enums.basic.StorehousePermissionEnum;
import com.canaan.business.common.enums.inOutStock.*;
import com.canaan.business.domain.basic.StorehousePermission;
import com.canaan.business.domain.bill.AdjustInBill;
import com.canaan.business.domain.bill.RefundProductBill;
import com.canaan.business.domain.bill.SalesRefundBill;
import com.canaan.business.domain.bill.ScrapProductBill;
import com.canaan.business.domain.inOutStock.*;
import com.canaan.business.domain.invoice.WmsProStockApply;
import com.canaan.business.domain.vo.distributeYardageVo;
import com.canaan.business.mapper.inOutStock.WmsInStockDetailOrderMapper;
import com.canaan.business.service.basic.IStorehousePermissionService;
import com.canaan.business.service.bill.IAdjustInBillService;
import com.canaan.business.service.bill.IRefundProductBillService;
import com.canaan.business.service.bill.ISalesRefundBillService;
import com.canaan.business.service.bill.IScrapProductBillService;
import com.canaan.business.service.inOutStock.IWmsInStockDetailOrderService;
import com.canaan.business.service.inOutStock.IWmsInStockOrderService;
import com.canaan.business.service.inOutStock.IYardageGoodsTaskOrderService;
import com.canaan.business.service.invoice.IWmsProStockApplyService;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.TableNoUtil;
import com.canaan.system.service.ISysConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 入库单明细Service业务层处理
 *
 * @author ruoyi
 * @date 2022-12-20
 */
@Service
public class WmsInStockDetailOrderServiceImpl implements IWmsInStockDetailOrderService
{
    @Resource
    private WmsInStockDetailOrderMapper wmsInStockDetailOrderMapper;
    @Resource
    private IYardageGoodsTaskOrderService yardageGoodsTaskOrderService;
    @Resource
    private IWmsInStockOrderService wmsInStockOrderService;
    @Resource
    private IStorehousePermissionService storehousePermissionService;


    @Resource
    private IWmsProStockApplyService wmsProStockApplyService;
    @Resource
    private IRefundProductBillService refundProductBillService;
    @Resource
    private IScrapProductBillService scrapProductBillService;
    @Resource
    private ISalesRefundBillService salesRefundBillService;
    @Resource
    private IAdjustInBillService adjustInBillService;

    @Resource
    private ISysConfigService sysConfigService;


    /**
     * 查询入库单明细
     *
     * @param id 入库单明细主键
     * @return 入库单明细
     */
    @Override
    public WmsInStockDetailOrder selectWmsInStockDetailOrderById(Long id)
    {
        return wmsInStockDetailOrderMapper.selectWmsInStockDetailOrderById(id);
    }

    /**
     * 查询入库单明细列表
     *
     * @param wmsInStockDetailOrder 入库单明细
     * @return 入库单明细
     */
    @Override
    public List<WmsInStockDetailOrder> selectWmsInStockDetailOrderList(WmsInStockDetailOrder wmsInStockDetailOrder)
    {
        return wmsInStockDetailOrderMapper.selectWmsInStockDetailOrderList(wmsInStockDetailOrder);
    }

    /**
     * 新增入库单明细
     *
     * @param wmsInStockDetailOrder 入库单明细
     * @return 结果
     */
    @Override
    public int insertWmsInStockDetailOrder(WmsInStockDetailOrder wmsInStockDetailOrder)
    {
        WmsInStockDetailOrder select = new WmsInStockDetailOrder();
        select.setProductNo(wmsInStockDetailOrder.getProductNo());
        select.setOrderNo(wmsInStockDetailOrder.getOrderNo());
        List<WmsInStockDetailOrder> list = wmsInStockDetailOrderMapper.selectWmsInStockDetailOrderList(select);
        if(!list.isEmpty()){
            throw new ServiceException("物料不能重复");
        }

        wmsInStockDetailOrder.setNo(TableNoUtil.getNo(WmsInStockDetailOrder.class));
        wmsInStockDetailOrder.setCreateBy(SecurityUtils.getUsername());
        wmsInStockDetailOrder.setCreateTime(DateUtils.getNowDate());
        wmsInStockDetailOrder.setOrderDetailStatus(InOrderStatusEnum.NEW.getCode());
        return wmsInStockDetailOrderMapper.insertWmsInStockDetailOrder(wmsInStockDetailOrder);
    }

    @Override
    public WmsInStockDetailOrder gettWmsInStockDetailOrderByPnAndOrderNo(String productNo, String orderNo) {
        WmsInStockDetailOrder query = new WmsInStockDetailOrder();
        query.setProductNo(productNo);
        query.setOrderNo(orderNo);
        List<WmsInStockDetailOrder> detailOrders =  this.wmsInStockDetailOrderMapper.selectWmsInStockDetailOrderList(query);
        if (CollectionUtil.isNotEmpty(detailOrders)){
            WmsInStockDetailOrder detailOrder = detailOrders.get(0);
            return detailOrder;
        }else{
            return null;
        }

    }

    /**
     * 修改入库单明细
     *
     * @param wmsInStockDetailOrder 入库单明细
     * @return 结果
     */
    @Override
    public int updateWmsInStockDetailOrder(WmsInStockDetailOrder wmsInStockDetailOrder)
    {
        wmsInStockDetailOrder.setUpdateTime(DateUtils.getNowDate());
        wmsInStockDetailOrder.setUpdateBy(SecurityUtils.getUsername());
        return wmsInStockDetailOrderMapper.updateWmsInStockDetailOrder(wmsInStockDetailOrder);
    }

    /**
     * 批量删除入库单明细
     *
     * @param ids 需要删除的入库单明细主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteWmsInStockDetailOrderByIds(Long[] ids)
    {
        WmsInStockDetailOrder detailOrder = new WmsInStockDetailOrder();
        detailOrder.setIds(Arrays.asList(ids));
        List<WmsInStockDetailOrder> list = wmsInStockDetailOrderMapper.selectWmsInStockDetailOrderList(detailOrder);
        if(list.isEmpty()){
            return 0;
        }else{
            //校验详情对应的码货单
            List<String> errorNos = list.stream()
                    .filter(e -> e.getActualQty() != null && e.getActualQty() > 0)
                    .map(WmsInStockDetailOrder::getProductNo).collect(Collectors.toList());
            if(!errorNos.isEmpty()) {
                throw new ServiceException("已有实际入库数量的数据不能删除");
            }
        }

        int response = wmsInStockDetailOrderMapper.deleteWmsInStockDetailOrderByIds(ids);
        if(response > 0){
            //删除关联的码货单
            String[] delNos = list.stream().map(WmsInStockDetailOrder::getYardageGoodsOrderNo).toArray(String[]::new);
            yardageGoodsTaskOrderService.deleteYardageGoodsTaskOrderByNos(delNos);
        }
        return response;
    }

    /**
     * 删除入库单明细信息
     *
     * @param id 入库单明细主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteWmsInStockDetailOrderById(Long id)
    {
        WmsInStockDetailOrder detailOrder = wmsInStockDetailOrderMapper.selectWmsInStockDetailOrderById(id);
        if(detailOrder == null){
            return 0;
        }else if(detailOrder.getActualQty() > 0){
            throw new ServiceException("已有实际入库数量的数据不能删除");
        }
        int response = wmsInStockDetailOrderMapper.deleteWmsInStockDetailOrderById(id);
        if(response > 0 && StringUtils.isNotBlank(detailOrder.getYardageGoodsOrderNo())){
            yardageGoodsTaskOrderService.deleteYardageGoodsTaskOrderByNo(detailOrder.getYardageGoodsOrderNo());
        }
        return response;
    }

    /**
     * 根据入库单列表删除详情信息
     *
     * @param nos 入库单编号列表
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteByOrderNos(List<String> nos) {
        if(com.canaan.common.utils.StringUtils.isEmpty(nos)){
            return 0;
        }
        WmsInStockDetailOrder detailOrder = new WmsInStockDetailOrder();
        detailOrder.setNos(nos);
        List<WmsInStockDetailOrder> list = this.selectWmsInStockDetailOrderList(detailOrder);
        //检查有没有关联的码货单
        String[] yardageGoodsOrderNos = list.stream().map(WmsInStockDetailOrder::getYardageGoodsOrderNo)
                .filter(e -> !StringUtils.isEmpty(e)).toArray(String[]::new);
        if(yardageGoodsOrderNos.length > 0){
            //有关联的码货单就删掉
            yardageGoodsTaskOrderService.deleteYardageGoodsTaskOrderByNos(yardageGoodsOrderNos);
        }
        return wmsInStockDetailOrderMapper.deleteByOrderNos(nos);
    }

    /**
     * 分配码货
     *
     * @param entity 分配信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int distributeYardageGoods(distributeYardageVo entity){
        //判断是否已有码货单，有就获取数据，没有就初始数据
        WmsInStockDetailOrder order = wmsInStockDetailOrderMapper.selectWmsInStockDetailOrderById(entity.getId());
        if(order == null){
            throw new ServiceException("该明细不存在");
        }
        if (StringUtils.isEmpty(entity.getStorehouseNo())){
            throw new ServiceException("仓库不能为空");
        }
        if (entity.getDistributeQty()==null){
            throw new ServiceException("分配数量不能为空");
        }
        //判断码货单的分配数量是否大于申请数量
        List<YardageGoodsTaskOrder> yardageGoodsTaskOrderList = yardageGoodsTaskOrderService.selectByInOrderId(order.getId());
        //总分配数量
        Long totalDistributeQty = 0L;
        if (CollectionUtil.isNotEmpty(yardageGoodsTaskOrderList)){
            totalDistributeQty = yardageGoodsTaskOrderList.stream().map(e -> e.getDistributeQty()).reduce(Long::sum).get();
        }
        totalDistributeQty = totalDistributeQty + entity.getDistributeQty();
        if(totalDistributeQty>order.getOrderQty()){
            throw new ServiceException("分配总数不能大于入库申请数量");
        }
        String inStorehouseType = sysConfigService.selectConfigByKey("tactic.instorage");
        if (StringUtils.isEmpty(entity.getStorehouseLocationNo())){
            if(!"1".equals(inStorehouseType) && !"2".equals(inStorehouseType)){
                throw new ServiceException("与入库规则不符，需按指定库位码货!");
            }
        }
            //获取主表数据
            WmsInStockOrder wmsInStockOrder = new WmsInStockOrder();
            wmsInStockOrder.setNo(order.getOrderNo());
            List<WmsInStockOrder> orderList = wmsInStockOrderService.selectWmsInStockOrderList(wmsInStockOrder);
            if(orderList.isEmpty()){
                throw new ServiceException("主表数据不存在");
            }
            wmsInStockOrder = orderList.get(0);
            //校验入库权限
            this.storehousePermissionCheckout(entity.getStorehouseNo(), wmsInStockOrder.getOrderType());
            //初始码货单数据
            YardageGoodsTaskOrder add = new YardageGoodsTaskOrder();
            add.setArea(wmsInStockOrder.getArea());
            add.setOrderType(wmsInStockOrder.getOrderType());
            add.setOrderStatus(YardageGoodsOrderStatusEnum.CREATE.getCode());
            add.setRelOrderNo(wmsInStockOrder.getRelOrderNo());
            add.setProductNo(entity.getProductNo());
            add.setOrderQty(order.getOrderQty());
            add.setStorehouseNo(entity.getStorehouseNo());
            add.setStorehouseLocationNo(entity.getStorehouseLocationNo());
            add.setShipper(entity.getShipper());
            add.setInOrderId(order.getId());
            add.setDistributeQty(entity.getDistributeQty());
            //新增码货单
            yardageGoodsTaskOrderService.insertYardageGoodsTaskOrder(add);
            //保存码货单的编号
            WmsInStockDetailOrder updateDetailOrder = new WmsInStockDetailOrder();
            updateDetailOrder.setId(entity.getId());
            updateDetailOrder.setYardageGoodsOrderNo(add.getNo());
            updateDetailOrder.setOrderDetailStatus(InOrderStatusEnum.DISTRIBUTE.getCode());
            this.updateWmsInStockDetailOrder(updateDetailOrder);
            //如果主表数据状态是新建就要改成分配中
            if(InOrderStatusEnum.NEW.getCode().equals(wmsInStockOrder.getOrderStatus())){
                wmsInStockOrder.setOrderStatus(InOrderStatusEnum.DISTRIBUTE.getCode());
                wmsInStockOrderService.updateWmsInStockOrder(wmsInStockOrder);
                //处理来源单据的状态,除了收货和待检
                Integer status = InOrderStatusEnum.PICKING.getCode();
                if(!StringUtils.isEmpty(wmsInStockOrder.getRelOrderNo())
                        && InStockOrderTypeEnum.PRODUCTION.getCode().equals(wmsInStockOrder.getOrderType())){
                    //生产入库单
                    WmsProStockApply apply = wmsProStockApplyService.selectWmsProStockApplyByNo(wmsInStockOrder.getRelOrderNo());
                    if(apply != null && !status.equals(apply.getOrderStatus())){
                        apply.setOrderStatus(status);
                        wmsProStockApplyService.updateWmsProStockApply(apply);
                    }
                }else if(!StringUtils.isEmpty(wmsInStockOrder.getRelOrderNo())
                        && InStockOrderTypeEnum.STORES_RETURNED.getCode().equals(wmsInStockOrder.getOrderType())){
                    //退料单
                    RefundProductBill bill = refundProductBillService.selectRefundProductBillByNo(wmsInStockOrder.getRelOrderNo());
                    if(bill != null && !status.equals(bill.getStatus())){
                        bill.setStatus(status);
                        refundProductBillService.updateRefundProductBill(bill);
                    }
                }else if(!StringUtils.isEmpty(wmsInStockOrder.getRelOrderNo())
                        && InStockOrderTypeEnum.SCRAP.getCode().equals(wmsInStockOrder.getOrderType())){
                    //报废单
                    ScrapProductBill bill = scrapProductBillService.selectScrapProductBillByNo(wmsInStockOrder.getRelOrderNo());
                    if(bill != null && !status.equals(bill.getStatus())){
                        bill.setStatus(status);
                        scrapProductBillService.updateScrapProductBill(bill);
                    }
                }else if(!StringUtils.isEmpty(wmsInStockOrder.getRelOrderNo())
                        && InStockOrderTypeEnum.SALES_REFUND.getCode().equals(wmsInStockOrder.getOrderType())){
                    //销售退货单
                    SalesRefundBill bill = salesRefundBillService.selectSalesRefundBillByNo(wmsInStockOrder.getRelOrderNo());
                    if(bill != null && !status.equals(bill.getStatus())){
                        bill.setStatus(status);
                        salesRefundBillService.updateSalesRefundBill(bill);
                    }
                }else if(!StringUtils.isEmpty(wmsInStockOrder.getRelOrderNo())
                        && InStockOrderTypeEnum.ALLOCATE.getCode().equals(wmsInStockOrder.getOrderType())){
                    //调拨
                    AdjustInBill bill = adjustInBillService.selectAdjustInBillByNo(wmsInStockOrder.getRelOrderNo());
                    if(bill != null && !status.equals(bill.getStatus())){
                        bill.setStatus(status);
                        adjustInBillService.updateAdjustInBill(bill);
                    }
                }
            }
            return 1;

    }

    @Override
    public int confirmDistribute(Long id) {
        WmsInStockDetailOrder inStockDetailOrder = this.wmsInStockDetailOrderMapper.selectWmsInStockDetailOrderById(id);
        if (inStockDetailOrder==null){
            throw new ServiceException("找不到明细数据");
        }
        //校验是否有分配码货员
        List<YardageGoodsTaskOrder> yardageGoodsTaskOrderList = this.yardageGoodsTaskOrderService.selectByInOrderId(inStockDetailOrder.getId());
        if (CollectionUtil.isEmpty(yardageGoodsTaskOrderList)){
            throw new ServiceException("请先分配码货员");
        }else{
            //将所有拣货单状态调整为待检
            yardageGoodsTaskOrderList.stream().forEach(e->{
                e.setOrderStatus(OutOrderStatusEnum.WAITING_PICK.getCode());
            });
            this.yardageGoodsTaskOrderService.batchUpdateYardageGoodsTaskOrder(yardageGoodsTaskOrderList);
            inStockDetailOrder.setOrderDetailStatus(InOrderStatusEnum.PICKING.getCode());
            this.wmsInStockDetailOrderMapper.updateWmsInStockDetailOrder(inStockDetailOrder);
        }
        return 1;
    }

    @Override
    public int batchInsertInStockDetailOrder(List<WmsInStockDetailOrder> wmsInStockDetailOrders) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (WmsInStockDetailOrder inStockDetailOrder : wmsInStockDetailOrders){
            if(com.canaan.common.utils.StringUtils.isBlank(inStockDetailOrder.getNo())){
                inStockDetailOrder.setNo(TableNoUtil.getNo(WmsInStockDetailOrder.class));
            }
            inStockDetailOrder.setCreateBy(username);
            inStockDetailOrder.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i=0; i<wmsInStockDetailOrders.size();) {
            int endIndex = i+500;
            if (endIndex > wmsInStockDetailOrders.size()) {
                endIndex = wmsInStockDetailOrders.size();
            }
            insertNum = insertNum + wmsInStockDetailOrderMapper.batchInsertInStockDetailOrder(wmsInStockDetailOrders.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }


    /**
     * 仓库权限校验
     * @param storehouseNo  仓库编号
     * @param type          入库类型
     */
    private void storehousePermissionCheckout(String storehouseNo, Integer type){
        //校验仓库是否具有权限
        StorehousePermission permission = storehousePermissionService.getPermissionsByStorehouseNo(storehouseNo);
        if(permission == null){
            return;
        }
        List<String> permissionDetails = Arrays.asList(permission.getPermissionDetail().split(","));
        List<String> inPermissionList = Arrays.asList(
                StorehousePermissionEnum.IN_PRODUCTION.getCode().toString(),
                StorehousePermissionEnum.IN_STORES_RETURNED.getCode().toString(),
                StorehousePermissionEnum.IN_SCRAP.getCode().toString(),
                StorehousePermissionEnum.IN_SALES_REFUND.getCode().toString(),
                StorehousePermissionEnum.IN_WAIT_INSPECTION.getCode().toString(),
                StorehousePermissionEnum.IN_RECEIVING.getCode().toString(),
                StorehousePermissionEnum.IN_ALLOCATE.getCode().toString(),
                StorehousePermissionEnum.IN_OTHER.getCode().toString()
        );
        //权限校验
        if(inPermissionList.size() >= type && permissionDetails.contains(inPermissionList.get(type - 1))){
            return;
        }
        throw new ServiceException("该仓库权限不足");
    }

}
